// ISybiScript.h : Declaration of the CSybiScript

#ifndef __SYBISCRIPT_H_
#define __SYBISCRIPT_H_

#include "resource.h"       // main symbols

#define KEYLENGTH  0x00280000
#define ENCRYPT_ALGORITHM CALG_RC4

class _bstr_t_decrypt: public _bstr_t
{
public:
	_bstr_t_decrypt( HCRYPTKEY &hKey, const wchar_t* olestr ) : _bstr_t( olestr )
	{
		BOOL bResult;
		char *pNormalBlockBegin = (char *) (*this);
		char *pNormalBlockEnd = pNormalBlockBegin;

		_bstr_t decrypted_str("");

		while(pNormalBlockEnd[0] != 0x00)
		{
			if(pNormalBlockEnd[0] == 0x01) 
			{
				// add previous normal block into decrypted string
				pNormalBlockEnd[0] = 0x00;
				decrypted_str += _bstr_t(pNormalBlockBegin);

				pNormalBlockEnd++;
				// search end of the encrypt block
				char *pEncryptBlockEnd = pNormalBlockEnd;
				while(pEncryptBlockEnd[0] != 0x01) pEncryptBlockEnd++;
				DWORD dwEncryptBlockLength = pEncryptBlockEnd - pNormalBlockEnd;

				// the next normal block begin
				pNormalBlockBegin = pEncryptBlockEnd + 1;
				pNormalBlockEnd = pEncryptBlockEnd; // will be incremented at the end of the cycle

				// 
				DWORD dwEncryptBufferSize = dwEncryptBlockLength * sizeof(char) + 1;
				char *pszEncryptBuffer = new char[dwEncryptBufferSize];
				memset(pszEncryptBuffer, 0, dwEncryptBufferSize);

				memcpy(pszEncryptBuffer, pEncryptBlockEnd - dwEncryptBlockLength, dwEncryptBlockLength);

				// decode the encrypt
				CBase64 base64;
				DWORD dwDecodedBufferSize = base64.CalculateRecquiredDecodeOutputBufferSize(pszEncryptBuffer);
				char *pbEncryptBuffer = new char[dwDecodedBufferSize + 1];
				memset(pbEncryptBuffer, 0, dwDecodedBufferSize + 1);

				base64.DecodeBuffer( pszEncryptBuffer, pbEncryptBuffer);
				delete[] pszEncryptBuffer;

				bResult = CryptDecrypt( hKey, 0, true, 0, (PBYTE) pbEncryptBuffer, &dwDecodedBufferSize);

				// add decrypted block into decrypted string
				decrypted_str += _bstr_t(pbEncryptBuffer);
				delete[] pbEncryptBuffer;
			}
			pNormalBlockEnd++;
		}
		decrypted_str += _bstr_t(pNormalBlockBegin);

		(_bstr_t&)(*this) = decrypted_str;
	}
};

/////////////////////////////////////////////////////////////////////////////
// CSybiScript
class ATL_NO_VTABLE CSybiScript : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CSybiScript, &CLSID_SybiScript>,
	public IObjectSafetyImpl<CSybiScript, INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
	public ISybiScript,
	public IActiveScript,
	public IActiveScriptParse,
	public IServiceProvider,
	public IActiveScriptParseProcedure
{
public:
	CSybiScript() : m_pass(NULL), m_hKey(NULL), m_hCryptProv(NULL)
	{
		/*
		FILE *file = fopen("c:\\temp\\c.txt", "at");
		fwrite( "contructor", 1, 1, file);
		fclose( file );
		*/
	}

DECLARE_REGISTRY_RESOURCEID(IDR_SYBISCRIPT)
DECLARE_NOT_AGGREGATABLE(CSybiScript)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSybiScript)
	COM_INTERFACE_ENTRY(ISybiScript)
	COM_INTERFACE_ENTRY(IActiveScriptParse)
	COM_INTERFACE_ENTRY(IActiveScript)
	COM_INTERFACE_ENTRY(IActiveScriptParseProcedure)
	COM_INTERFACE_ENTRY(IServiceProvider)
	COM_INTERFACE_ENTRY(IObjectSafety)
	COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
END_COM_MAP()

public:
	CComPtr<IUnknown> m_pUnkMarshaler;
	CComPtr<IUnknown> m_pScriptEngine;
	CComPtr<IActiveScript> m_pIActiveScript;
	CComPtr<IActiveScriptParse> m_pIActiveScriptParse;
	CComPtr<IActiveScriptParseProcedure> m_pIActiveScriptParseProcedure;
	//CComPtr<IServiceProvider> m_pIServiceProvider;
	CComPtr<IObjectSafety> m_pIObjectSafety;

	HCRYPTPROV	m_hCryptProv; 
	HCRYPTKEY	m_hKey;

	CSybiScriptPassword m_pass;
	CScriptEvaluation14Days	m_eval;

public:
	HRESULT FinalConstruct()
	{
		/*
		FILE *file = fopen("c:\\temp\\a.txt", "at");
		char temp[255] = {0}, szError[255] = {0};
		LPVOID lpMsgBuf;
		*/

		CLSID clsid = {NULL};
		CLSIDFromString(_T("{B54F3743-5B07-11CF-A4B0-00AA004A55E8}"), &clsid);
		m_pScriptEngine.CoCreateInstance(clsid);

		m_eval.resetState();

		//
		BOOL	bResult;
		bResult = CryptAcquireContext( &m_hCryptProv, NULL, NULL, 
			PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
		
/*
if (!FormatMessageA( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPSTR) &lpMsgBuf,
    0,
    NULL ))
{}
		sprintf(temp, "%d, %d, %s\n", m_hCryptProv, bResult, lpMsgBuf);
		fwrite( temp, 1, strlen(temp), file);
LocalFree(lpMsgBuf);
*/
		IUnknown *pUnknown = NULL;
		m_pScriptEngine->QueryInterface(IID_IActiveScript, (void**) &pUnknown);
		m_pIActiveScript.Attach((IActiveScript *) pUnknown);

		HCRYPTHASH hHash;

		bResult = CryptCreateHash( m_hCryptProv, CALG_MD5, 0, 0, &hHash);
/*
if (!FormatMessageA( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    szError,
    0,
    NULL ))
{}
		sprintf(temp, "%d, %d, %s\n", hHash, bResult, lpMsgBuf);
		fwrite( temp, 1, strlen(temp), file);
LocalFree(lpMsgBuf);
*/
		m_pScriptEngine->QueryInterface(IID_IActiveScriptParse, (void**) &pUnknown);
		m_pIActiveScriptParse.Attach((IActiveScriptParse *) pUnknown);

		bResult = CryptHashData( hHash, (BYTE *)m_pass.get(), strlen(m_pass.get()), 0);

/*
if (!FormatMessageA( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    szError,
    0,
    NULL ))
{}
		sprintf(temp, "%d, %d, %s\n", hHash, bResult, lpMsgBuf);
		fwrite( temp, 1, strlen(temp), file);
LocalFree(lpMsgBuf);
*/

		IID IID_IActiveScriptParseProcedure2_32 = {NULL};
		IIDFromString(_T("{71EE5B20-FB04-11D1-B3A8-00A0C911E8B2}"), &IID_IActiveScriptParseProcedure2_32);
		m_pScriptEngine->QueryInterface(IID_IActiveScriptParseProcedure2_32, (void**) &pUnknown);
		m_pIActiveScriptParseProcedure.Attach((IActiveScriptParseProcedure *) pUnknown);

		bResult = CryptDeriveKey( m_hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, &m_hKey);
/*
if (!FormatMessageA( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    szError,
    0,
    NULL ))
{}
		sprintf(temp, "%d, %d, %s\n", m_hKey, bResult, lpMsgBuf);
		fwrite( temp, 1, strlen(temp), file);
LocalFree(lpMsgBuf);
*/
		m_pScriptEngine->QueryInterface(IID_IObjectSafety, (void**) &pUnknown);
		m_pIObjectSafety.Attach((IObjectSafety *) pUnknown);

		CryptDestroyHash(hHash);

		//fclose(file);

/*

		FILE *file = fopen("c:\\temp\\a.txt", "at");
		fwrite( "1", 1, 1, file);


		CLSID clsid = {NULL};
		CLSIDFromString(_T("{B54F3743-5B07-11CF-A4B0-00AA004A55E8}"), &clsid);
		m_pScriptEngine.CoCreateInstance(clsid);

		if(m_pScriptEngine != NULL) fwrite( "0", 1, 1, file);

		IUnknown *pUnknown = NULL;
		m_pScriptEngine->QueryInterface(IID_IActiveScript, (void**) &pUnknown);
		m_pIActiveScript.Attach((IActiveScript *) pUnknown);

		m_pScriptEngine->QueryInterface(IID_IActiveScriptParse, (void**) &pUnknown);
		m_pIActiveScriptParse.Attach((IActiveScriptParse *) pUnknown);

		IID IID_IActiveScriptParseProcedure2_32 = {NULL};
		IIDFromString(_T("{71EE5B20-FB04-11D1-B3A8-00A0C911E8B2}"), &IID_IActiveScriptParseProcedure2_32);
		m_pScriptEngine->QueryInterface(IID_IActiveScriptParseProcedure2_32, (void**) &pUnknown);
		m_pIActiveScriptParseProcedure.Attach((IActiveScriptParseProcedure *) pUnknown);

		m_pScriptEngine->QueryInterface(IID_IObjectSafety, (void**) &pUnknown);
		m_pIObjectSafety.Attach((IObjectSafety *) pUnknown);

		fwrite( "2", 1, 1, file);

		fclose(file);
*/
		return S_OK;
	}

	HRESULT FinalRelease()
	{
		CryptReleaseContext( m_hCryptProv, 0);

		return S_OK;
	}

public:
	// IObjectSafety
	HRESULT STDMETHODCALLTYPE SetInterfaceSafetyOptions( REFIID riid, DWORD dwOptionsSetMask, DWORD dwEnabledOptions );
	HRESULT STDMETHODCALLTYPE GetInterfaceSafetyOptions( REFIID riid, DWORD* pdwSupportedOptions, DWORD* pdwEnabledOptions );

	// IActiveScript
    HRESULT STDMETHODCALLTYPE SetScriptSite( 
        /* [in] */ IActiveScriptSite __RPC_FAR *pass);
    
    HRESULT STDMETHODCALLTYPE GetScriptSite( 
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
    
    HRESULT STDMETHODCALLTYPE SetScriptState( 
        /* [in] */ SCRIPTSTATE ss);
    
    HRESULT STDMETHODCALLTYPE GetScriptState( 
        /* [out] */ SCRIPTSTATE __RPC_FAR *pssState);
    
    HRESULT STDMETHODCALLTYPE Close( void);
    
    HRESULT STDMETHODCALLTYPE AddNamedItem( 
        /* [in] */ LPCOLESTR pstrName,
        /* [in] */ DWORD dwFlags);
    
    HRESULT STDMETHODCALLTYPE AddTypeLib( 
        /* [in] */ REFGUID rguidTypeLib,
        /* [in] */ DWORD dwMajor,
        /* [in] */ DWORD dwMinor,
        /* [in] */ DWORD dwFlags);
    
    HRESULT STDMETHODCALLTYPE GetScriptDispatch( 
        /* [in] */ LPCOLESTR pstrItemName,
        /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdisp);
    
    HRESULT STDMETHODCALLTYPE GetCurrentScriptThreadID( 
        /* [out] */ SCRIPTTHREADID __RPC_FAR *pstidThread);
    
    HRESULT STDMETHODCALLTYPE GetScriptThreadID( 
        /* [in] */ DWORD dwWin32ThreadId,
        /* [out] */ SCRIPTTHREADID __RPC_FAR *pstidThread);
    
    HRESULT STDMETHODCALLTYPE GetScriptThreadState( 
        /* [in] */ SCRIPTTHREADID stidThread,
        /* [out] */ SCRIPTTHREADSTATE __RPC_FAR *pstsState);
    
    HRESULT STDMETHODCALLTYPE InterruptScriptThread( 
        /* [in] */ SCRIPTTHREADID stidThread,
        /* [in] */ const EXCEPINFO __RPC_FAR *pexcepinfo,
        /* [in] */ DWORD dwFlags);
    
    HRESULT STDMETHODCALLTYPE Clone( 
        /* [out] */ IActiveScript __RPC_FAR *__RPC_FAR *ppscript);

	// IActiveScriptParse
	HRESULT STDMETHODCALLTYPE InitNew( void);
    
    HRESULT STDMETHODCALLTYPE AddScriptlet( 
        /* [in] */ LPCOLESTR pstrDefaultName,
        /* [in] */ LPCOLESTR pstrCode,
        /* [in] */ LPCOLESTR pstrItemName,
        /* [in] */ LPCOLESTR pstrSubItemName,
        /* [in] */ LPCOLESTR pstrEventName,
        /* [in] */ LPCOLESTR pstrDelimiter,
        /* [in] */ DWORD dwSourceContextCookie,
        /* [in] */ ULONG ulStartingLineNumber,
        /* [in] */ DWORD dwFlags,
        /* [out] */ BSTR __RPC_FAR *pbstrName,
        /* [out] */ EXCEPINFO __RPC_FAR *pexcepinfo);
    
    HRESULT STDMETHODCALLTYPE ParseScriptText( 
        /* [in] */ LPCOLESTR pstrCode,
        /* [in] */ LPCOLESTR pstrItemName,
        /* [in] */ IUnknown __RPC_FAR *punkContext,
        /* [in] */ LPCOLESTR pstrDelimiter,
        /* [in] */ DWORD dwSourceContextCookie,
        /* [in] */ ULONG ulStartingLineNumber,
        /* [in] */ DWORD dwFlags,
        /* [out] */ VARIANT __RPC_FAR *pvarResult,
        /* [out] */ EXCEPINFO __RPC_FAR *pexcepinfo);

    // IActiveScriptParseProcedure
	HRESULT STDMETHODCALLTYPE ParseProcedureText( 
            /* [in] */ LPCOLESTR pstrCode,
            /* [in] */ LPCOLESTR pstrFormalParams,
            /* [in] */ LPCOLESTR pstrProcedureName,
            /* [in] */ LPCOLESTR pstrItemName,
            /* [in] */ IUnknown __RPC_FAR *punkContext,
            /* [in] */ LPCOLESTR pstrDelimiter,
            /* [in] */ DWORD dwSourceContextCookie,
            /* [in] */ ULONG ulStartingLineNumber,
            /* [in] */ DWORD dwFlags,
            /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdisp);

	// IServiceProvider
	HRESULT STDMETHODCALLTYPE QueryService(
			REFGUID guidService,
			REFIID riid,
			void **ppv);
};

#endif //__SYBISCRIPT_H_
